package com.woniuxy.book.interceptor;

import com.woniuxy.book.util.JWTUtil;
import com.woniuxy.book.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;

@Component
public class MyInterceptor implements HandlerInterceptor {

    @Resource
    private RedisUtil redisUtil;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //跳过预检
        if(request.getMethod().equals("OPTIONS")){
            return true;
        }
        //取出请求头中的token
        String accessToken = request.getHeader("token");
        if(accessToken==null) {
            throw new Exception("请先登录");
        }
        //尝试解析token
        try {
            JWTUtil.parseToken(accessToken);
        } catch (ExpiredJwtException e) {
            //短token过期
            //获取长token
            String refreshToken = redisUtil.get(accessToken);
            if (refreshToken==null) {
                //长token过期
                throw e;
            }else {
                //长token未过期 重新签发短token
                Claims claims = JWTUtil.parseToken(refreshToken);//如果jwt本身过期 也会抛出异常
                Object subject = claims.get("subject");
                Object role = claims.get("role");
                HashMap<String, Object> map = new HashMap<>();
                map.put("subject",subject);
                map.put("role",role);
                accessToken = JWTUtil.createToken(map, 30);//短token有效时间30分钟
                //重新签发短token
                //将token响应给客户端
                response.setHeader("token",accessToken);
                //使用短token为键 长token为值存储到redis中
                redisUtil.set(accessToken,refreshToken,3*24*60*60);//长token在redis中的有效期为三天，这里设置的时间不影响长token的有效时间
                //暴露自定义响应头给前端
                response.setHeader("Access-Control-Expose-Headers","token");

            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
